#ifndef __SCENE_H
#define __SCENE_H
#include <vector>

namespace RAYTRACER{

struct material {
    float reflection, power;
	Color diffuse , specular;
};

class _ray {
public:
	_ray () {}
	_ray (const _ray & r): start (r.start), dir(r.dir) {}
	_ray (const Point3 & p, const Vector3 & v) : start(p), dir(v) {}
	Point3 start;
	Vector3 dir;
};

typedef _ray Ray ;

class _sphere {
public:
	Point3 pos;
	float size;
	int materialId;

	bool intersect(const _ray &r, float &t) 
	{ 
		Vector3 dist = this->pos - r.start; 
		float B = r.dir * dist;
		float D = B*B - dist * dist + this->size * this->size; 
		if (D < 0.0f) 
		    return false; 
		float t0 = B - sqrtf(D); 
		float t1 = B + sqrtf(D);
		bool retvalue = false;  
		if ((t0 > 0.1f) && (t0 < t)) 
		{
		    t = t0;
		    retvalue = true; 
		} 
		if ((t1 > 0.1f) && (t1 < t)) 
		{
		    t = t1; 
		    retvalue = true; 
		}
		return retvalue; 
	}

	Vector3 get_normal (Point3 & surfacePos)
	{
        Vector3 n = surfacePos - pos;
        float temp = n * n;
        temp = 1.0f / sqrtf(temp); 
        return n = temp * n; 
	}
};

typedef _sphere sphere; 

struct light {
	Point3 pos;
	Color color ;
};

class _scene {
public :
	bool intersect (const Ray & ray, Point3 & newStart, Vector3 & normal, int & sphereIdx, int & materialId)
	{
        float t = 2000.0f;
        sphereIdx= -1;
        for (unsigned int i = 0; i < this->sphereContainer.size(); ++i) 
        { 
			if (this->sphereContainer[i].intersect(ray,t))
            {
                sphereIdx = i;
            }
        }
        if (sphereIdx == -1) return false;
		newStart = ray.start + t * ray.dir;
		normal = this->sphereContainer[sphereIdx].get_normal(newStart);
		materialId = this->sphereContainer[sphereIdx].materialId ;
		return true;
	} 
public :
    std::vector<material> materialContainer;
	std::vector<sphere>   sphereContainer;
	std::vector<light>    lightContainer;
    int sizex, sizey;
};

typedef _scene scene ;

const Vector3 NullVector = Vector3( 0.0f,0.0f,0.0f );
const Point3 Origin = Point3(  0.0f,0.0f,0.0f );

bool init(scene & myScene)
{
	int nbMats, nbSpheres, nbLights;
	int i;
	
    myScene.sizex = 640; 
    myScene.sizey = 480; 

    nbMats =  3 ; 
    nbSpheres = 3 ;
    nbLights = 2; 

	myScene.materialContainer.resize(nbMats);
	myScene.sphereContainer.resize(nbSpheres);
	myScene.lightContainer.resize(nbLights);

	myScene.materialContainer[0].diffuse = Color (1.0f, 1.0f, 0.0f);	
	myScene.materialContainer[0].specular = Color (1.0f, 1.0f, 1.0f);
	myScene.materialContainer[0].power = 60 ;
	myScene.materialContainer[0].reflection = 0.5f; 

	myScene.materialContainer[1].diffuse = Color (0.0f, 1.0f, 1.0f);	
	myScene.materialContainer[1].specular = Color (1.0f, 1.0f, 1.0f);
	myScene.materialContainer[1].power = 60 ;
	myScene.materialContainer[1].reflection = 0.5f;

	myScene.materialContainer[2].diffuse = Color (1.0f, 0.0f, 1.0f);	
	myScene.materialContainer[2].specular = Color (1.0f, 1.0f, 1.0f);
	myScene.materialContainer[2].power = 60 ;
	myScene.materialContainer[2].reflection = 0.5f;


	myScene.sphereContainer[0].pos = Point3 (233.0f, 290.0f, 0.0);
	myScene.sphereContainer[0].size = 100.0f; 
	myScene.sphereContainer[0].materialId =  0;

	myScene.sphereContainer[1].pos = Point3 (407.0f, 290.0f, 0.0);
	myScene.sphereContainer[1].size = 100.0f; 
	myScene.sphereContainer[1].materialId =  1;

	myScene.sphereContainer[2].pos = Point3 (320.0f, 140.0f, 0.0);
	myScene.sphereContainer[2].size = 100.0f; 
	myScene.sphereContainer[2].materialId =  2;

	myScene.lightContainer[0].pos = Point3 (0.0, 240, -100.0);
	myScene.lightContainer[0].color = Color ( 1.0f, 1.0f, 1.0f);

	myScene.lightContainer[1].pos = Point3 (640, 240, -10000.0);
	myScene.lightContainer[1].color = Color ( .6f, .7f, 1.0f);

	return true;
}

}
#endif // __SCENE_H
